﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace AutoLoL.Entities
{
    public class InibinEntry
    {
        public InibinEntry(uint key, byte[] buffer, int segmentType, int valueOffset, int dataOffset, int bitNumber)
        {
            Key = key;
            Buffer = buffer;
            SegmentType = segmentType;
            ValueOffset = valueOffset;
            DataOffset = dataOffset;
            BitNumber = bitNumber;
        }

        public uint Key { get; private set; }

        public byte[] Buffer { get; private set; }

        public int SegmentType { get; private set; }

        public int ValueOffset { get; private set; }

        public int DataOffset { get; private set; }

        public int BitNumber { get; private set; }

        // http://www.leagueoflegends.com/board/showthread.php?t=258251&page=6
        //  0 -> int32
        //  1 -> single
        //  2 -> byte (value/10)
        //  3 -> int16
        //  4 -> byte
        //  5 -> bool
        // 10 -> uint32
        // 12 -> uint16 (offset -> string)

        // http://www.leagueoflegends.com/board/showthread.php?t=178173&page=17
        // 6 = Each key matches three 8bit values (RGB/BGR?)
        // 7 = Each key matches three 32bit values; possibly single-precision float values (XYZ coordinates?)
        // 8 = Still Unknown (not used in any inibin files... perhaps in troybin?)
        // 9 = Still Unknown (not used in any inibin files... perhaps in troybin?)
        // 10 = Each key matches one 32bit integer or four 8bit values (RGBA/BGRA?)
        // 11 = Each key matches four 32bit values; possibly single-precision float values (Rect coordinates? (Top-Left Bottom-Right))
        public static int[] SegmentSizes = { 
            4, 4, 1, 2, 1, -1, 1, 12, 0, 0, 4, 16, 2, 0, 0, 0
        };

        public uint GetInt32()
        {
            byte[] buffer = this.Buffer;
            int offset = this.ValueOffset;

            try
            {
                Int32 adasd = BitConverter.ToInt32(buffer, offset);
                adasd.ToString();
            }
            catch { if (Debugger.IsAttached) throw; }

            UInt32 u32 = BitConverter.ToUInt32(buffer, offset);
            return u32;
        }

        public byte GetInt8()
        {
            byte[] buffer = this.Buffer;
            int offset = this.ValueOffset;

            byte b = buffer[offset];
            return b;
        }

        public uint GetInt16()
        {
            byte[] buffer = this.Buffer;
            int offset = this.ValueOffset;

            try
            {
                Int16 adasdd = BitConverter.ToInt16(buffer, offset);
                adasdd.ToString();
            }
            catch { if (Debugger.IsAttached) throw; }

            UInt16 u16 = BitConverter.ToUInt16(buffer, offset);
            return u16;
        }

        public uint GetByte10()
        {
            byte[] buffer = this.Buffer;
            int offset = this.ValueOffset;

            uint value = ((uint)buffer[offset]) * 10;
            return value;
        }

        public float GetFloat()
        {
            byte[] buffer = this.Buffer;
            int offset = this.ValueOffset;

            float value = BitConverter.ToSingle(buffer, offset);
            return value;
        }

        public bool GetBit()
        {
            bool bit = ((Buffer[ValueOffset] & (1 << BitNumber)) != 0);
            return bit;
        }

        public string GetHex()
        {
            byte[] buffer = this.Buffer;
            int offset = this.ValueOffset;
            int length = InibinEntry.SegmentSizes[this.SegmentType];

            StringBuilder sb = new StringBuilder();
            bool first = true;
            while (length > 0)
            {
                if (!first)
                {
                    sb.Append(' ');
                }

                first = false;
                sb.Append(buffer[offset].ToString("x2"));
                offset++;
                length--;
            }

            return sb.ToString();
        }

        public string GetString()
        {
            byte[] buffer = this.Buffer;
            int index = this.DataOffset;

            int length = 0;
            while (true)
            {
                if (buffer[index + length] == 0)
                {
                    break;
                }

                length++;
            }

            string value = Encoding.ASCII.GetString(buffer, index, length);
            StringBuilder sb = new StringBuilder();

            foreach (char c in value)
            {
                if (c == '"')
                {
                    sb.Append("\\\"");
                }
                else if ((uint)c >= 32 && (uint)c <= 127)
                {
                    sb.Append(c);
                }
                else
                {
                    sb.Append("\\x").Append(unchecked((byte)c).ToString("x2"));
                }
            }

            return sb.ToString();
        }

        public override string ToString()
        {
            string result = null;

            switch (SegmentType)
            {
                case 0:
                case 10:
                    result = GetInt32().ToString();
                    break;
                case 1:
                    result = GetFloat().ToString("g");
                    break;
                case 2:
                    result = GetByte10().ToString();
                    break;
                case 3:
                    result = GetInt16().ToString();
                    break;
                case 4:
                    result = GetInt8().ToString();
                    break;
                case 5:
                    result = GetBit().ToString();
                    break;
                case 12:
                    result = GetString();
                    break;
                default:
                    result = GetHex();
                    break;
            }

            return result;
        }
    }
}
